﻿using AutoMapper;
using ManagementApi.Authorizers;
using ManagementApi.Models;
using ManagementApi.Models.Manage.ProjectCorp;
using ManagementApi.Models.Manage.ProjectGroup;
using ManagementApi.Models.Manage.ProjectGroupMember;
using ManagementApi.Mvc;
using ManagementApi.Mvc.ApplicationContexts;
using ManagementApi.Mvc.Filters;
using ManagementApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Modules;
using Modules.Corp;
using Modules.Device;
using Modules.Device.Entitys;
using Modules.Person;
using Modules.Project;
using Modules.Project.Entitys;
using NPOI.SS.UserModel;
using PmSoft;
using PmSoft.Entity;
using PmSoft.Exceptions;
using PmSoft.Utilities;
using System.ComponentModel.DataAnnotations;
using static Modules.Device.CheckInDeviceConstants;
using static Modules.Person.PersonConstants;

namespace ManagementApi.Controllers.CommanderPannel
{
    /// <summary>
    /// 劳务组管理接口
    /// </summary>
    [Route("/api/v1/commander/projectgroup")]
    [ApiController]
    [Authorize(Roles = "Commander")]
    [TypeFilter(typeof(RequireSelProjectActionFilter))]
    public class ProjectGroupController : ControllerBase
    {
        private readonly ProjectGroupService projectGroupService;
        private readonly ProjectGroupMemberService projectGroupMemberService;
        private readonly ProjectCommanderApplicationContext applicationContext;
        private readonly IMapper mapper;
        private readonly CheckinDeviceService projectCheckinDeviceService;
        private readonly CheckinDeviceCommandService projectCheckinDeviceCommandService;
        private readonly PersonService personService;
        private readonly ProjectCorpService projectCorpService;
        private readonly ProjectOwnAuthorizer ownAuthorizer;

        public ProjectGroupController(ProjectGroupMemberService projectGroupMemberService, ProjectGroupService projectGroupService, ProjectCommanderApplicationContext applicationContext, IMapper mapper, CheckinDeviceService projectCheckinDeviceService, CheckinDeviceCommandService projectCheckinDeviceCommandService, PersonService personService, ProjectCorpService projectCorpService, ProjectOwnAuthorizer ownAuthorizer)
        {
            this.projectGroupMemberService = projectGroupMemberService;
            this.projectGroupService = projectGroupService;
            this.applicationContext = applicationContext;
            this.mapper = mapper;
            this.projectCheckinDeviceService = projectCheckinDeviceService;
            this.projectCheckinDeviceCommandService = projectCheckinDeviceCommandService;
            this.personService = personService;
            this.projectCorpService = projectCorpService;
            this.ownAuthorizer = ownAuthorizer;
        }

        /// <summary>
        /// 班组下拉
        /// </summary>
        /// <param name="corpId"></param>
        /// <returns></returns>
        [HttpGet("pulldown/{corpId}")]
        public ApiResult<IEnumerable<LabelValue<int>>> GetPullDown(int? corpId)
        {
            IEnumerable<ProjectGroup> projectGroups = projectGroupService.GetProjectGroupsByProjectId(applicationContext.CurrentProjectInfo.ProjectId);
            if (corpId.HasValue)
            {
                projectGroups = projectGroups.Where(a => a.CorpId == corpId);
            }
            var dtos = projectGroups.AsPullDownDtos();
            return ApiResult<IEnumerable<LabelValue<int>>>.Success(dtos);
        }

        /// <summary>
        /// 获取当前项目的所有班组
        /// </summary>
        /// <returns></returns>
        [HttpGet("corp_group_by_name")]
        public ApiResult<CorpGroupDto> GetProjectCorpsByName(string name)
        {
            int projectId = applicationContext.CurrentProjectInfo.ProjectId;
            IEnumerable<ProjectGroup> data = projectGroupService.SearchGoups(projectId, name);
            return ApiResult<CorpGroupDto>.Success(data.AsCorpGroupDto(applicationContext.CurrentProjectInfo, applicationContext));
        }

        #region 一键进出场

        /// <summary>
        /// 一键进场
        /// </summary>
        /// <param name="groupIds">班组id</param>
        /// <returns></returns>
        [HttpPut("enterArena/{groupIds}")]
        public ApiResult EnterArena(string groupIds)
        {
            IEnumerable<ProjectGroupMember> projectGroupMembers = projectGroupMemberService.GetProjectGroupMembersByGroupIds(ValueUtility.ConvertToList<int>(groupIds));

            #region 验证数据权限

            ownAuthorizer.CheckAndThrowIfOwnAuthenticationFailed(projectGroupMembers.Select(i => i.ProjectId));

            #endregion 验证数据权限

            projectGroupMembers = projectGroupMembers.Where(a => a.Status == 进出场状态.离场 && a.ProjectId == applicationContext.CurrentProjectInfo.ProjectId);

            IEnumerable<PersonInfo> personInfos = personService.GetPersons(projectGroupMembers.Select(a => a.PersonId).Distinct());

            #region 下发人员信息到设备

            if (personInfos.Count() > 0)
            {
                IEnumerable<CheckinDevice> devices = projectCheckinDeviceService.GetProjectCheckinDevicesByProjectId(applicationContext.CurrentProjectInfo.ProjectId);
                foreach (var device in devices)
                {
                    CheckinDeviceCommand log = new CheckinDeviceCommand()
                    {
                        Name = 考勤机命令.人员进场后下发.GetDescription(),
                        Code = 考勤机命令.人员进场后下发,
                        MessageId = Guid.NewGuid().ToString(),
                        DeviceCode = device.Code,
                        Status = 命令下发状态.待下发,
                        IsAuto = true
                    };
                    projectCheckinDeviceCommandService.Send(log, device, personInfos);
                }
            }

            #endregion 下发人员信息到设备

            projectGroupMemberService.Update(projectGroupMembers, 进出场状态.进场);
            return ApiResult.Success("操作成功");
        }

        /// <summary>
        /// 一键离场
        /// </summary>
        /// <param name="groupIds">班组id</param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        [HttpPut("appearStage/{groupIds}")]
        public ApiResult AppearStage(string groupIds, [Required(ErrorMessage = "离场时间不能为空")] DateTime endDate)
        {
            IEnumerable<ProjectGroupMember> projectGroupMembers = projectGroupMemberService.GetProjectGroupMembersByGroupIds(ValueUtility.ConvertToList<int>(groupIds));

            #region 验证数据权限

            ownAuthorizer.CheckAndThrowIfOwnAuthenticationFailed(projectGroupMembers.Select(i => i.ProjectId));

            #endregion 验证数据权限

            projectGroupMembers = projectGroupMembers.Where(a => a.Status == 进出场状态.进场 && a.ProjectId == applicationContext.CurrentProjectInfo.ProjectId);

            IEnumerable<PersonInfo> personInfos = personService.GetPersons(projectGroupMembers.Select(a => a.PersonId).Distinct());

            #region 下发人员信息到设备

            if (personInfos.Count() > 0)
            {
                IEnumerable<CheckinDevice> devices = projectCheckinDeviceService.GetProjectCheckinDevicesByProjectId(applicationContext.CurrentProjectInfo.ProjectId);
                foreach (var device in devices)
                {
                    CheckinDeviceCommand log = new CheckinDeviceCommand()
                    {
                        Name = 考勤机命令.人员离场后下发.GetDescription(),
                        Code = 考勤机命令.人员离场后下发,
                        MessageId = Guid.NewGuid().ToString(),
                        DeviceCode = device.Code,
                        Status = 命令下发状态.待下发,
                        IsAuto = true
                    };
                    projectCheckinDeviceCommandService.Send(log, device, personInfos);
                }
            }

            #endregion 下发人员信息到设备

            foreach (var item in projectGroupMembers)
            {
                item.EndDate = endDate;
            }
            projectGroupMemberService.Update(projectGroupMembers, 进出场状态.离场);
            return ApiResult.Success("操作成功");
        }

        #endregion 一键进出场

        /// <summary>
        /// 获取当前项目的参建单位（总包+分包）
        /// </summary>
        /// <returns></returns>
        [HttpGet("getProjectCorps")]
        public ApiResult<IEnumerable<VueTree<int>>> GetProjectCorp()
        {
            int projectId = applicationContext.CurrentProjectInfo.ProjectId;
            var corps = applicationContext.GetService<CorpService>().GetCorpsByProjectId(projectId);
            var vueTrees = corps.Select(item => new VueTree<int>
            {
                Label = item.Name,
                Id = item.CorpId,
                Extend1 = "Corp",
                Icon = "address-card",
                Value = item.CorpId,
            });
            return ApiResult<IEnumerable<VueTree<int>>>.Success(vueTrees);
        }

        /// <summary>
        /// 根据企业Id获取班组信息
        /// </summary>
        /// <param name="corpId"></param>
        /// <param name="Keywords"></param>
        /// <returns></returns>
        [HttpGet("getProjectGroups")]
        public ApiResult<IEnumerable<ProjectGroupDto>> GetProjectGroups(int? corpId, string? Keywords)
        {
            int projectId = applicationContext.CurrentProjectInfo.ProjectId;
            List<ProjectGroupMember> projectGroupMembers = new();
            List<ProjectGroupDto> projectGroups = new();
            if (corpId.HasValue)
            {
                projectGroupMembers = projectGroupMemberService.GetProjectGroupMembersByCorpIdsAndProjectId(ValueUtility.ConvertToList<int>(corpId.ToString() ?? string.Empty), projectId).ToList();
                projectGroups = projectGroupService.GetProjectGroupsByCordProjectId(projectId, ValueUtility.ConvertToList<int>(corpId.ToString() ?? string.Empty)).AsDtos(projectGroupMembers).ToList();
            }
            else
            {
                projectGroupMembers = projectGroupMemberService.GetProjectGroupMembersByProjectId(projectId).ToList();
                projectGroups = projectGroupService.GetProjectGroupsByProjectId(projectId).AsDtos(projectGroupMembers).ToList();
            }
            if (!string.IsNullOrWhiteSpace(Keywords))
                projectGroups = projectGroups.Where(a => a.Name.Contains(Keywords)).ToList();
            return ApiResult<IEnumerable<ProjectGroupDto>>.Success(projectGroups.OrderBy(a => a.CorpName));
        }

        /// <summary>
        /// 根据班组id获取成员信息
        /// </summary>
        /// <param name="groupId"></param>
        /// <returns></returns>
        [HttpGet("getProjectGroupMembers")]
        public ApiResult<IEnumerable<ProjectGroupMemberDto>> GetProjectGroupMembers([Required(ErrorMessage = "班组不能为空")] int groupId)
        {
            IEnumerable<ProjectGroupMemberDto> projectGroupMembers = projectGroupMemberService.GetProjectGroupMembersByGroupId(groupId).AsProjectGroupMemberDtos().OrderByDescending(a => a.IsLeader).OrderByDescending(a => a.CreateTime);
            return ApiResult<IEnumerable<ProjectGroupMemberDto>>.Success(projectGroupMembers);
        }

        /// <summary>
        /// 获取班组人员信息分页
        /// </summary>
        /// <param name="query"></param>
        /// <param name="pageNum"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [HttpGet("page")]
        public ApiResult<PageDto<ProjectGroupMemberDto>> QueryProjectGroupMembers([FromQuery] ProjectGroupMemberQuery query, int pageNum = 1, int pageSize = 20)
        {
            query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
            var data = projectGroupMemberService.GetProjectGroupMembers(query, pageNum, pageSize);
            return ApiResult<PageDto<ProjectGroupMemberDto>>.Success(data.AsPageDto(a => a.AsProjectGroupMemberDto()));
        }

        /// <summary>
        /// 根据班组Id获取班组列表
        /// </summary>
        /// <param name="groupId"></param>
        /// <returns></returns>
        [HttpGet("getProjectGroupsByGroupId")]
        public ApiResult<IEnumerable<ProjectGroupDto>> GetProjectGroups(int groupId)
        {
            ProjectGroup? projectGroup = projectGroupService.GetProjectGroup(groupId);
            if (projectGroup == null) projectGroup = new ProjectGroup();
            List<ProjectGroupDto> dtos = new() {
            projectGroup.AsDto(applicationContext)
            };
            return ApiResult<IEnumerable<ProjectGroupDto>>.Success(dtos);
        }

        /// <summary>
        /// 删除班组
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        [HttpDelete("{ids}")]
        public ApiResult Delete(string ids)
        {
            var data = projectGroupService.GetProjectGroups(ValueUtility.ConvertToList<int>(ids));

            #region 验证数据权限

            ownAuthorizer.CheckAndThrowIfOwnAuthenticationFailed(data.Select(i => i.ProjectId));

            #endregion 验证数据权限

            projectGroupService.DeleteProjectGroups(ValueUtility.ConvertToList<int>(ids));
            return ApiResult.Success("删除成功");
        }

        /// <summary>
        /// 班组表单数据
        /// </summary>
        /// <param name="id">角色ID</param>
        /// <returns></returns>
        [HttpGet("{id}/form")]
        public ApiResult<ProjectGroupEditForm> GetProjectGroup(int id)
        {
            ProjectGroup data = projectGroupService.GetProjectGroup(id);
            if (data == null)
                return ApiResult<ProjectGroupEditForm>.Failure("班组不存在");
            ProjectGroupEditForm form = new ProjectGroupEditForm();
            mapper.Map(data, form);
            form.CorpName = applicationContext.GetService<CorpService>().GetCorpInfo(data.CorpId)?.Name;
            return ApiResult<ProjectGroupEditForm>.Success(form);
        }

        /// <summary>
        /// 新增班组
        /// </summary>
        /// <param name="form"></param>
        /// <returns></returns>
        //[HttpPost("create")]
        //public ApiResult CreateProjectGroup(ProjectGroupEditForm form)
        //{
        //    ProjectCorp? projectCorp = projectCorpService.GetProjectCorpByProjectIdAndCorpId(applicationContext.CurrentProjectInfo.ProjectId, form.CorpId ?? 0);
        //    if (projectCorp == null)
        //        return ApiResult.Failure("参建单位信息不存在");
        //    if (projectCorp.Role == 项目参建单位类型.监理)
        //        return ApiResult.Failure("监理企业不能新增班组");

        //    ProjectGroup entity = new();
        //    mapper.Map(form, entity);
        //    entity.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
        //    entity.CreateTime = DateTime.Now;
        //    projectGroupService.CreateProjectGroup(entity);
        //    return ApiResult.Success("创建成功");
        //}

        /// <summary>
        /// 编辑班组
        /// </summary>
        /// <param name="id"></param>
        /// <param name="form"></param>
        /// <returns></returns>
        [HttpPut("{id}")]
        public ApiResult UpdateProjectGroup(int id, ProjectGroupEditForm form)
        {
            ProjectGroup data = projectGroupService.GetProjectGroup(id) ?? throw new BusinessException("班组不存在");

            #region 验证数据权限

            ownAuthorizer.CheckAndThrowIfOwnAuthenticationFailed(data.ProjectId);

            #endregion 验证数据权限

            mapper.Map(form, data);
            data.GroupId = id;
            projectGroupService.UpdateProjectGroup(data);
            return ApiResult.Success("修改成功");
        }

        /// <summary>
        /// 更改人员所在班组
        /// </summary>
        /// <param name="form"></param>
        /// <returns></returns>
        [HttpPut("editPersonGroup")]
        public ApiResult EditPersonGroupMember(EditPersonGroupMemberForm form)
        {
            ProjectGroup data = projectGroupService.GetProjectGroup(form.NewGroupId) ?? throw new BusinessException("新班组不存在");

            #region 验证数据权限

            ownAuthorizer.CheckAndThrowIfOwnAuthenticationFailed(data.ProjectId);

            #endregion 验证数据权限

            ProjectGroup data2 = projectGroupService.GetProjectGroup(form.OldGroupId) ?? throw new BusinessException("旧班组不存在");

            #region 验证数据权限

            ownAuthorizer.CheckAndThrowIfOwnAuthenticationFailed(data2.ProjectId);

            #endregion 验证数据权限

            if (form.OldGroupId == form.NewGroupId)
                return ApiResult.Failure("不能变更到原班组");
            if (form.StartDate <= DateTime.Now.Date)
                return ApiResult.Failure("进场日期不能小于等于当前日期");
            if (form.StartDate > form.EndDate)
                return ApiResult.Failure("进场日期不能大于离场日期");
            projectGroupMemberService.EditPersonGroupMember(applicationContext.CurrentProjectInfo.ProjectId, form.PersonId, form.OldGroupId, form.NewGroupId, form.StartDate, form.EndDate);
            return ApiResult.Success("人员班组更换成功");
        }

        /// <summary>
        /// 单个人员进场
        /// </summary>
        /// <param name="memberId"></param>
        /// <returns></returns>
        [HttpPut("inGroupMember/{memberId}")]
        public ApiResult InGroupMember(int memberId)
        {
            var data = projectGroupMemberService.GetMember(memberId) ?? throw new BusinessException("人员不存在");

            #region 验证数据权限

            ownAuthorizer.CheckAndThrowIfOwnAuthenticationFailed(data.ProjectId);

            #endregion 验证数据权限

            projectGroupMemberService.InGroupMember(memberId);
            return ApiResult.Success("人员进场成功");
        }

        /// <summary>
        /// 单个人员离场
        /// </summary>
        /// <param name="memberId"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        [HttpPut("outGroupMember/{memberId}")]
        public ApiResult OutGroupMember(int memberId, [Required(ErrorMessage = "离场时间不能为空")] DateTime endDate)
        {
            var data = projectGroupMemberService.GetMember(memberId) ?? throw new BusinessException("人员不存在");

            #region 验证数据权限

            ownAuthorizer.CheckAndThrowIfOwnAuthenticationFailed(data.ProjectId);

            #endregion 验证数据权限

            projectGroupMemberService.OutGroupMember(memberId, endDate);
            return ApiResult.Success("人员离场成功");
        }

        /// <summary>
        /// 导出Excel
        /// </summary>
        /// <returns></returns>
        [HttpGet("export")]
        public IActionResult Export()
        {
            int projectId = applicationContext.CurrentProjectInfo.ProjectId;
            List<ProjectGroupMemberExportDto> exportDtos = projectGroupMemberService.GetProjectGroupMembersByProjectId(projectId).AsExportDtos().ToList();
            IWorkbook workbook = ExcelExportHelper.ExportToExcel(exportDtos);

            // 将工作簿保存到内存流中
            using (MemoryStream memoryStream = new MemoryStream())
            {
                workbook.Write(memoryStream);
                // 返回文件内容结果
                return File(memoryStream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"班组成员信息表_{DateTime.Now.ToString("yyyyMMddHHmmss ")}.xlsx");
            }
        }
    }
}